package com.fezz.plugins;

import com.fezz.constant.Constant;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.Plugin;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.Interface;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.api.dom.xml.Element;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.internal.util.StringUtility;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * 备注插件
 *
 * @author <a href="mailto:fezz_ggjp@163.com">fezz</a>
 * @version $Id$
 * @since 1.0
 */
public class CommentPlugin extends PluginAdapter {

    /**
     * This method is called after all the setXXX methods are called, but before
     * any other method is called. This allows the plugin to determine whether
     * it can run or not. For example, if the plugin requires certain properties
     * to be set, and the properties are not set, then the plugin is invalid and
     * will not run.
     *
     * @param warnings add strings to this list to specify warnings. For example, if
     *                 the plugin is invalid, you should specify why. Warnings are
     *                 reported to users after the completion of the run.
     * @return true if the plugin is in a valid state. Invalid plugins will not
     * be called
     */
    @Override
    public boolean validate(List<String> warnings) {
        return true;
    }

    @Override
    public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        List javaDocLines = topLevelClass.getJavaDocLines();
        javaDocLines.clear();
        String tableName = introspectedTable.getTableConfiguration().getTableName();
        if (StringUtility.stringHasValue(tableName)) {
            //添加domain的import
            topLevelClass.addImportedType("com.alibaba.fastjson.annotation.JSONField");
            topLevelClass.addImportedType("lombok.Data");
            topLevelClass.addImportedType("org.apache.ibatis.type.Alias");
            topLevelClass.addImportedType("javax.persistence.GeneratedValue");
            topLevelClass.addImportedType("javax.persistence.Id");
            topLevelClass.addImportedType("javax.persistence.OrderBy");
            topLevelClass.addImportedType("javax.persistence.Table");

            topLevelClass.addJavaDocLine("");
            topLevelClass.addJavaDocLine("/**");
            topLevelClass.addJavaDocLine(" * TODO");
            topLevelClass.addJavaDocLine(" *");
            topLevelClass.addJavaDocLine(" * @author muyun");
            topLevelClass.addJavaDocLine(" * @version 1.0.0");
            // topLevelClass.addJavaDocLine(" * @since " + new SimpleDateFormat("yyyy/MM/dd").format(new Date()));
            topLevelClass.addJavaDocLine(" */");
            topLevelClass.addJavaDocLine("@Data");

            // 处理别名
            String alias = "";
            alias = tableName.replaceAll("sm_", "").replaceAll("auth_", "")
                    .replaceAll("wy_", "")
                    .replaceAll("sys_", "").replaceAll("_", "");

            topLevelClass.addJavaDocLine("@Alias(\"" + alias + "\")");
            topLevelClass.addJavaDocLine("@Table(name = \"" + tableName + "\")");
        }
        return super.modelBaseRecordClassGenerated(topLevelClass, introspectedTable);
    }

    @Override
    public boolean modelFieldGenerated(Field field, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, Plugin.ModelClassType modelClassType) {
        List javaDocLines = field.getJavaDocLines();
        javaDocLines.clear();

        String remarks = introspectedColumn.getRemarks();
        if (StringUtility.stringHasValue(remarks)) {
            field.addJavaDocLine("/** " + remarks + " */");
        }

        // 添加主键的注解@Id
        if (introspectedColumn.isAutoIncrement()) {
            field.addJavaDocLine("@Id");
            field.addJavaDocLine("@OrderBy(\"DESC\")");
            field.addJavaDocLine("@GeneratedValue(generator = \"JDBC\")");
        }

        String name = field.getName();
        if (Constant.CREATE_TIME_ATTR.equals(name) || Constant.UPDATE_TIME_ATTR.equals(name)
                || Constant.CREATE_TIME_ATTR_2.equals(name) || Constant.UPDATE_TIME_ATTR_2.equals(name)) {
            // Set<FullyQualifiedJavaType> importedTypes = topLevelClass.getImportedTypes();
            // FullyQualifiedJavaType fullyQualifiedJavaType = new FullyQualifiedJavaType("org.springframework.format.annotation.DateTimeFormat");
            // if (!importedTypes.contains(fullyQualifiedJavaType)){
            //     topLevelClass.addImportedType(fullyQualifiedJavaType);
            // }
            field.addJavaDocLine("@JSONField(format = \"yyyy-MM-dd HH:mm:ss\")");
        }

        return super.modelFieldGenerated(field, topLevelClass, introspectedColumn, introspectedTable, modelClassType);
    }

    @Override
    public boolean modelGetterMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, Plugin.ModelClassType modelClassType) {
        // List javaDocLines = method.getJavaDocLines();
        // javaDocLines.clear();
        //
        // StringBuilder sb = new StringBuilder();
        // method.addJavaDocLine("/**");
        // sb.setLength(0);
        // sb.append(" * @return the value of ");
        // sb.append(introspectedColumn.getActualColumnName());
        // method.addJavaDocLine(sb.toString());
        // method.addJavaDocLine("*/");
        //
        // return super.modelGetterMethodGenerated(method, topLevelClass, introspectedColumn, introspectedTable, modelClassType);

        // 不生成Getter方法
        return false;
    }

    @Override
    public boolean modelSetterMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, Plugin.ModelClassType modelClassType) {
        // List javaDocLines = method.getJavaDocLines();
        // javaDocLines.clear();
        //
        // StringBuilder sb = new StringBuilder();
        // method.addJavaDocLine("/**");
        // Parameter parm = method.getParameters().get(0);
        // sb.setLength(0);
        // sb.append(" * @param ");
        // sb.append(parm.getName());
        // sb.append(" the value for ");
        // sb.append(introspectedColumn.getActualColumnName());
        // method.addJavaDocLine(sb.toString());
        // method.addJavaDocLine("*/");
        //
        // return super.modelSetterMethodGenerated(method, topLevelClass, introspectedColumn, introspectedTable, modelClassType);

        // 不生成Setter方法
        return false;
    }

    @Override
    public boolean clientInsertMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
        List javaDocLines = method.getJavaDocLines();
        javaDocLines.clear();
        return super.clientInsertMethodGenerated(method, interfaze, introspectedTable);
    }

    @Override
    public boolean clientInsertSelectiveMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
        List javaDocLines = method.getJavaDocLines();
        javaDocLines.clear();
        return super.clientInsertSelectiveMethodGenerated(method, interfaze, introspectedTable);
    }

    @Override
    public boolean clientUpdateByPrimaryKeySelectiveMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
        List javaDocLines = method.getJavaDocLines();
        javaDocLines.clear();
        return super.clientUpdateByPrimaryKeySelectiveMethodGenerated(method, interfaze, introspectedTable);
    }

    @Override
    public boolean clientSelectByPrimaryKeyMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
        List javaDocLines = method.getJavaDocLines();
        javaDocLines.clear();
        return super.clientSelectByPrimaryKeyMethodGenerated(method, interfaze, introspectedTable);
    }

    @Override
    public boolean clientDeleteByPrimaryKeyMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
        List javaDocLines = method.getJavaDocLines();
        javaDocLines.clear();
        return super.clientDeleteByPrimaryKeyMethodGenerated(method, interfaze, introspectedTable);
    }

    @Override
    public boolean clientUpdateByPrimaryKeyWithBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
        List javaDocLines = method.getJavaDocLines();
        javaDocLines.clear();
        return super.clientUpdateByPrimaryKeyWithBLOBsMethodGenerated(method, interfaze, introspectedTable);
    }

    @Override
    public boolean clientUpdateByPrimaryKeyWithoutBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
        List javaDocLines = method.getJavaDocLines();
        javaDocLines.clear();
        return super.clientUpdateByPrimaryKeyWithoutBLOBsMethodGenerated(method, interfaze, introspectedTable);
    }

    @Override
    public boolean sqlMapResultMapWithBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        clearElementDoc(element);
        return super.sqlMapResultMapWithBLOBsElementGenerated(element, introspectedTable);
    }

    @Override
    public boolean sqlMapResultMapWithoutBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        clearElementDoc(element);
        return super.sqlMapResultMapWithoutBLOBsElementGenerated(element, introspectedTable);
    }

    @Override
    public boolean sqlMapBaseColumnListElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        clearElementDoc(element);
        return super.sqlMapBaseColumnListElementGenerated(element, introspectedTable);
    }

    @Override
    public boolean sqlMapDeleteByPrimaryKeyElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        clearElementDoc(element);
        return super.sqlMapDeleteByPrimaryKeyElementGenerated(element, introspectedTable);
    }

    @Override
    public boolean sqlMapInsertElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        clearElementDoc(element);
        return super.sqlMapInsertElementGenerated(element, introspectedTable);
    }

    @Override
    public boolean sqlMapInsertSelectiveElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        clearElementDoc(element);
        return super.sqlMapInsertSelectiveElementGenerated(element, introspectedTable);
    }

    @Override
    public boolean sqlMapUpdateByPrimaryKeySelectiveElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        clearElementDoc(element);
        return super.sqlMapUpdateByPrimaryKeySelectiveElementGenerated(element, introspectedTable);
    }

    @Override
    public boolean sqlMapUpdateByPrimaryKeyWithBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        clearElementDoc(element);
        return super.sqlMapUpdateByPrimaryKeyWithBLOBsElementGenerated(element, introspectedTable);
    }

    @Override
    public boolean sqlMapUpdateByPrimaryKeyWithoutBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        clearElementDoc(element);
        return super.sqlMapUpdateByPrimaryKeyWithoutBLOBsElementGenerated(element, introspectedTable);
    }

    @Override
    public boolean sqlMapSelectByPrimaryKeyElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        clearElementDoc(element);
        return super.sqlMapSelectByPrimaryKeyElementGenerated(element, introspectedTable);
    }

    /**
     * 清除元素文档
     *
     * @param element XmlElement
     */
    private void clearElementDoc(XmlElement element) {
        List elements = element.getElements();
        Iterator iterator = elements.iterator();

        while (iterator.hasNext()) {
            Element next = (Element) iterator.next();
            if ((next instanceof TextElement)) {
                TextElement textElement = (TextElement) next;
                String content = textElement.getContent();
                if ((content.indexOf("<!--") >= 0) ||
                        (content.indexOf("WARNING - @mbg.generated") >= 0) ||
                        (content.indexOf("This element is automatically generated by MyBatis Generator, do not modify.") > 0) ||
                        (content.indexOf("This element was generated on") >= 0) ||
                        (content.indexOf("-->") >= 0)) {
                    iterator.remove();
                }
            }
        }
    }
}
